using System.Data;

namespace Crux.Core.Dapper.Test;
public partial class UnitOfWorkTest
{
    private readonly IUnitOfWork<TestContext> unitOfWork;
    private readonly IQueryRepository<TestContext> repository;
    public UnitOfWorkTest(
        IUnitOfWork<TestContext> unitOfWork,
        IQueryRepository<TestContext> repository)
    {
        this.unitOfWork = unitOfWork
            ?? throw new ArgumentNullException(nameof(unitOfWork));
        this.repository = repository
            ?? throw new ArgumentNullException(nameof(repository));
    }
    [Fact]
    public void BeginTransactionTest()
    {
        using var transaction = unitOfWork.BeginTransaction();

        transaction?.Rollback();

        Assert.NotNull(transaction);
    }
    [Fact]
    public void BeginTransactionWithIsolationLevelTest()
    {
        using var transaction = unitOfWork.BeginTransaction(IsolationLevel.Serializable);

        transaction?.Rollback();

        Assert.NotNull(transaction);
    }
    [Fact]
    public void SetTimeoutTest()
    {
        var _this = unitOfWork.SetTimeout(5);

        Assert.NotNull(_this);
    }
    [Fact]
    public void AddTest()
    {
        var entity = unitOfWork.Add(new TestNotice
        {
            Id = Guid.NewGuid()
        });

        Assert.NotNull(entity);
    }
    [Fact]
    public void AddWithTransactionRollback()
    {
        using var transaction = unitOfWork.BeginTransaction();

        var entity = unitOfWork.Add(new TestNotice
        {
            Id = Guid.NewGuid()
        });

        Assert.NotNull(entity);

        transaction.Rollback();
    }
    [Fact]
    public void AddWithTransactionCommit()
    {
        using var transaction = unitOfWork.BeginTransaction();

        var entity = unitOfWork.Add(new TestNotice
        {
            Id = Guid.NewGuid()
        });
        Assert.NotNull(entity);

        transaction.Commit();
    }
    [Fact]
    public async Task AddAsyncTest()
    {
        var entity = await unitOfWork.AddAsync(new TestModel
        {
            Password = "1"
        });

        Assert.NotNull(entity);
        Assert.True(entity.Id > 0);
    }
    [Fact]
    public async Task AddAsyncWithTransactionRollbackTest()
    {
        using var transaction = unitOfWork.BeginTransaction();
        var entity = await unitOfWork.AddAsync(new TestModel
        {
            Password = "1"
        });

        Assert.NotNull(entity);
        Assert.True(entity.Id > 0);

        transaction.Rollback();
    }
    [Fact]
    public async Task AddAsyncWithTransactionCommitTest()
    {
        using var transaction = unitOfWork.BeginTransaction();
        var entity = await unitOfWork.AddAsync(new TestModel
        {
            Password = $"{Random.Shared.Next(999999):000000}"
        });

        Assert.NotNull(entity);
        Assert.True(entity.Id > 0);

        transaction.Commit();
    }
    [Fact]
    public void AddRangeTest()
    {
        var effectRow = unitOfWork.AddRange(new List<TestNotice>{
                new TestNotice
                {
                    Id = Guid.NewGuid()
                },
                new TestNotice{
                    Id = Guid.NewGuid()
                },
                new TestNotice{
                    Id = Guid.NewGuid()
                },
                new TestNotice{
                    Id = Guid.NewGuid()
                },
                new TestNotice{
                    Id = Guid.NewGuid()
                }
            });

        Assert.True(effectRow > 0);
    }
    [Fact]
    public void AddRangeWithTransactionRollbackTest()
    {
        using var transaction = unitOfWork.BeginTransaction();

        var effectRow = unitOfWork.AddRange(new List<TestNotice>{
                new TestNotice
                {
                    Id = Guid.NewGuid()
                },
                new TestNotice{
                    Id = Guid.NewGuid()
                },
                new TestNotice{
                    Id = Guid.NewGuid()
                },
                new TestNotice{
                    Id = Guid.NewGuid()
                },
                new TestNotice{
                    Id = Guid.NewGuid()
                }
            });

        Assert.True(effectRow > 0);

        transaction.Rollback();
    }
    [Fact]
    public void AddRangeWithTransactionCommitTest()
    {
        using var transaction = unitOfWork.BeginTransaction();

        var effectRow = unitOfWork.AddRange(new List<TestNotice>{
                new TestNotice
                {
                    Id = Guid.NewGuid()
                },
                new TestNotice{
                    Id = Guid.NewGuid()
                },
                new TestNotice{
                    Id = Guid.NewGuid()
                },
                new TestNotice{
                    Id = Guid.NewGuid()
                },
                new TestNotice{
                    Id = Guid.NewGuid()
                }
            });

        Assert.True(effectRow > 0);

        transaction.Commit();
    }
    [Fact]
    public async Task AddRangeAsyncTest()
    {
        var effectRow = await unitOfWork.AddRangeAsync(GenericTestModel()).ConfigureAwait(false);

        Assert.True(effectRow > 0);
    }
    public IEnumerable<TestSoftDeleteModel> GenericTestModel()
    {
        foreach (var _ in Enumerable.Range(0, 1000))
        {
            yield return new TestSoftDeleteModel
            {
                // Password = $"{Random.Shared.Next(999999):000000}"
                UserName = $"{Random.Shared.Next(999999):000000}",
                Status = TestStatus.Active
            };
        }
    }
    [Fact]
    public async Task AddRangeAsyncWithTransactionRollbackTest()
    {
        using var transaction = unitOfWork.BeginTransaction();
        var effectRow = await unitOfWork.AddRangeAsync(GenericTestModel());

        Assert.True(effectRow > 0);

        transaction.Rollback();
    }
    [Fact]
    public async Task AddRangeAsyncWithTransactionCommitTest()
    {
        using var transaction = unitOfWork.BeginTransaction();
        var effectRow = await unitOfWork.AddRangeAsync(GenericTestModel());

        Assert.True(effectRow > 0);

        transaction.Commit();
    }
}